package ecom.shell.commandsImpl;

import ecom.beans.AccountBean;
import ecom.beans.EcomAdminRemote;
import ecom.beans.EcomCustomerRemote;
import ecom.beans.exception.DeviseException;
import ecom.shell.commandsImpl.OutputCommandImpl.Outputs;
import ecom.shell.exception.InsuffisantPrivilegeException;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringWriter;
import java.text.DecimalFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import shell.ShellCommand;
import shell.ShellContext;

public class AccountCommandImpl implements ShellCommand {
    

    private ShellContext _context = null;

    public AccountCommandImpl(ShellContext context) {
        _context = context;
    }

    @Override
    public String getName() {
        return "account";
    }

    @Override
    public String getUsage() {
        return "account";
    }

    @Override
    public String getShortDescription() {
        String commands = "Account commands\n";
        commands += "\t-help ..................................................get account commands description\n";
        if (true == _context.getVar("isAdmin")) {
            commands += "\t[without args] .........................................get all accounts\n";
            commands += "\t-add [iban] ............................................create an account\n";
            commands += "\t-remove [iban] .........................................delete an account\n";
        }
        commands += "\t-deposit [pseudo] [password] [amount] ..................deposit cash on account iban\n";
        commands += "\t-iban [iban] ...........................................display specified account details\n";
        return commands;
    }

    
    public String execute(String cmdline, PrintStream out, PrintStream err) throws InsuffisantPrivilegeException {
        StringBuilder result = new StringBuilder();
        EcomCustomerRemote ecomCustomerBean = (EcomCustomerRemote) _context.getVar("customerBean");
        EcomAdminRemote ecomAdminBean = (EcomAdminRemote) _context.getVar("adminBean");
        Outputs currentOutput = (Outputs) _context.getVar("output");
        String currentCurrency = (String) _context.getVar("currency");
        Set<AccountBean> accountList = null;
        StringTokenizer cmd = new StringTokenizer(cmdline, " ");

        cmd.nextToken();

        if (cmd.countTokens() == 0) {
            if (true != _context.getVar("isAdmin")) {
                throw new InsuffisantPrivilegeException();
            }
            accountList = ecomAdminBean.getAllAccounts();
            try {
                return getStringList(ecomCustomerBean, out, accountList, currentOutput, currentCurrency);
            } catch (DeviseException ex) {
                System.err.println("Error with getting all accounts : " + ex.getMessage());
            }
        } else {
            String arg = cmd.nextToken();

            if (arg.equals("-help")) {
                result.append(getShortDescription());
            } else if (arg.equals("-add")) {
                if (true != _context.getVar("isAdmin")) {
                    throw new InsuffisantPrivilegeException();
                }
                if (cmd.countTokens() == 1) {
                    try {
                        String iban;

                        iban = cmd.nextToken();

                        ecomAdminBean.createAccount(iban, new Double(0));
                        result.append("Account created with iban : ").append(iban);
                    } catch (Exception e) {
                        err.println("Error with account creation " + e.getMessage());
                    }
                } else {
                    err.println(EcomCommandsConstantes.INCORRECT_NUMBER_ARGS);
                }
            } else if (arg.equals("-remove")) {
                if (true != _context.getVar("isAdmin")) {
                    throw new InsuffisantPrivilegeException();
                }
                if (cmd.countTokens() == 1) {
                    try {
                        String iban = cmd.nextToken();
                        ecomAdminBean.removeAccount(iban);
                        result.append("Account iban : ").append(iban).append(" deleted");
                    } catch (Exception ex) {
                        err.println("Error with account deletion : " + ex.getMessage());
                    }
                } else {
                    err.println(EcomCommandsConstantes.INCORRECT_NUMBER_ARGS);
                }
            } else if (arg.equals("-iban")) {
                if (cmd.countTokens() == 1) {
                    try {
                        String iban = cmd.nextToken();
                        AccountBean account = ecomCustomerBean.getAccountById(iban);
                        return getTextAccount(ecomCustomerBean, out, account, currentOutput, currentCurrency);
                    } catch (Exception ex) {
                        err.println("Error with account detail : " + ex.getMessage());
                    }
                } else {
                    err.println(EcomCommandsConstantes.INCORRECT_NUMBER_ARGS);
                }
            } else if (arg.equals("-deposit")) {
                if (cmd.countTokens() == 3) {
                    try {
                        String pseudo = cmd.nextToken();
                        String password = cmd.nextToken();
                        Double amount = Double.valueOf(cmd.nextToken());
                        ecomCustomerBean.setUser(ecomCustomerBean.getUserByPseudoAndPassword(pseudo, password));
                        ecomCustomerBean.deposit(amount);
                        result.append("Money deposited whith iban : ").append(ecomCustomerBean.getUser().getAccount().getIban());
                        ecomCustomerBean.setUser(null);
                    } catch (NumberFormatException e) {
                        err.println("You have not enter a number for the amount");
                    } catch (Exception e) {
                        err.println("Error with account deposit : " + e.getMessage());
                    }
                } else {
                    err.println(EcomCommandsConstantes.INCORRECT_NUMBER_ARGS);
                }
            } else {
                err.println(arg + " is not known for Account Management");
            }
        }
        return result.toString();
    }

    private String getStringList(EcomCustomerRemote ecomCustomerBean, PrintStream out, Set<AccountBean> accountList, Outputs currentOutput, String currentCurrency) throws DeviseException {
        StringBuilder result = new StringBuilder();
        if (currentOutput.equals(Outputs.XML)) {
            Element accounts = new Element("accounts");
            org.jdom.Document document = new Document(accounts);

            for (AccountBean account : accountList) {
                accounts.addContent(createXMLNode(account, ecomCustomerBean, currentCurrency));
            }
            XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
            result.append(sortie.outputString(document));
        } else if (currentOutput.equals(Outputs.TEXT)) {
            for (AccountBean account : accountList) {
                result.append(getText(out, account, ecomCustomerBean, currentCurrency)).append("\n");
            }
        } else {
            result.append("Output format '").append(currentOutput).append("' is not implementing for this command");
        }
        return result.toString();
    }

    private String getTextAccount(EcomCustomerRemote ecomCustomerBean, PrintStream out, AccountBean a, Outputs currentOutput, String currentCurrency) throws DeviseException {
        Set<AccountBean> list = new HashSet<AccountBean>();
        list.add(a);
        return getStringList(ecomCustomerBean, out, list, currentOutput, currentCurrency);
    }

    private String getText(PrintStream out, AccountBean account, EcomCustomerRemote ecomCustomerBean, String currentCurrency) throws DeviseException {
        return account.toString() + " " + currentCurrency;
    }

    private Element createXMLNode(AccountBean a, EcomCustomerRemote ecomCustomerBean, String currentCurrency) throws DeviseException {
        Element account = new Element("account");
        Attribute id = new Attribute("iban", String.valueOf(a.getIban()));
        account.setAttribute(id);

        Element balance = new Element("balance");
        DecimalFormat myFormatter = new DecimalFormat("##0.00");
        balance.setText(myFormatter.format(ecomCustomerBean.convertFromEuro(a.getBalance(), currentCurrency)));
        Attribute currency = new Attribute("currency", currentCurrency);
        balance.setAttribute(currency);
        account.addContent(balance);

        return account;
    }

    
  
}
